<!--
  Copyright (C) 2009 Google Inc.

  Based on code of Allesandro Warth's OMeta/JS workspace.js file:
  http://tinlizzie.org/ometa-js
  The markup of the textfields is based on Doug Crockford's JSLint page:
  http://www.jslint.com
 
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
 
  http://www.apache.org/licenses/LICENSE-2.0
 
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

!-->

<html>
  <head>
    <title>ECMAScript 5 Parser</title>

    <!-- OMeta's lib.js overrides window.unescape, while
         Google Analytics requires the original definition.
         Alias the original version for use by GA below. -->
    <script type="text/javascript">
      this.original_unescape = window.unescape;
    </script>
    <script src="bundle.js"></script>
    <script>

function toggleVisible(id) {
  var style = document.getElementById(id).style
  style.visibility = style.visibility == "hidden" ? "visible" : "hidden"
  style.display    = style.display    == "block"  ? "none"    : "block"
}

function makeVisible(id) {
  var style = document.getElementById(id).style;
  style.visibility = "visible";
  style.display    = "block";
}

var example = "function fac(n){\n  if (n < 1) { return 1; } else { return n * fac(n-1); } }";

function $(id) { return document.getElementById(id); }

function initializeThisPage() {
  $('workspaceForm').source.value      = $('workspaceForm').source.origValue = example;
  $('workspaceForm').translation.value = ''
}

/* Get selection of textarea */
function getCaretSelection(field) {
    field.focus();
    var result = { start: 0, end: 0 };
    // IE support based on http://groups.drupal.org/node/1210
    if(typeof $('workspaceForm').source.selectionEnd == "undefined") {
      var range     = document.selection.createRange(),
          rangeCopy = range.duplicate()
      rangeCopy.moveToElementText(field)
      rangeCopy.setEndPoint( 'EndToEnd', range )
      result.start = rangeCopy.text.length - range.text.length
      result.end = result.start + range.text.length
    }
    else {
      result.start = field.selectionStart
      result.end   = field.selectionEnd
    }
    return result
}

/* Set selection of textarea */
function setCaretSelection(field, start, end) {
    field.focus()
    // IE
    if(typeof $('workspaceForm').source.selectionEnd == "undefined") {
      var range = field.createTextRange()
      range.expand("textedit")
      var dStart = start - (field.value.substring(0, start).split("\n").length - 1),
          dEnd   = end - field.value.length + field.value.substring(end + 1).split("\n").length - 1
      range.moveStart("character", dStart)
      range.moveEnd("character", dEnd)
      range.select()
    }
    else {
      field.selectionStart = start
      field.selectionEnd   = end
    }
}

/* Get expression from textarea */
function getSource() {
  var editor    = $('workspaceForm').source,
      selection = getCaretSelection(editor),
      start     = selection.start,
      end       = selection.end,
      text      = editor.value.substring(start, end)
  if (start == end) {
    // nothing selected -> parse entire input text
    start = 0;
    end = editor.value.length;
    text = editor.value;
    setCaretSelection(editor, start, end);
  }
  return {
    editor: editor,
    start:  start,
    end:    end,
    text:   text
  }
}

function getRule(radio) {
  if(!radio) return "";
  var l = radio.length;
  if (l == undefined) {
    return (radio.checked) ? radio.value : undefined;
  }
  for(var i = 0; i < l; i++) {
    if (radio[i].checked) { return radio[i].value; }
  }
  return undefined;
}

function parse(text, errFun) {
  ES5Parser.generatePositionInfo = $('positionInfo').checked;
  var rule = getRule($('workspaceForm').rules) || 'Program';
  return JSON.stringify(
    ES5Parser.matchAll(text, rule, [], errFun),
    undefined,
    2);
}

function parseIt() {
  var source = getSource(), result;
  $('workspaceForm').translation.value = result = parse(source.text, function(_, idx) {
    if (idx !== undefined) {
      var errorPos     = source.start + idx,
	  errorMsg     = " Parse error ->",
	  oldScrollTop = $('workspaceForm').source.scrollTop;
      $('workspaceForm').source.value =
        $('workspaceForm').source.value.substring(0, errorPos) + errorMsg +
	    $('workspaceForm').source.value.substring(errorPos, $('workspaceForm').source.value.length);
      $('workspaceForm').source.scrollTop = oldScrollTop;
      setCaretSelection($('workspaceForm').source, errorPos, errorPos + errorMsg.length);
    }
    $('workspaceForm').translation.value = "";
    $('workspaceForm').source.style.border = "2px solid red";
    throw new Error('Parse Error');
  });
  $('workspaceForm').source.style.border = "2px solid black";
  makeVisible('translation');
}
    </script>
  </head>
  
  <body onLoad="initializeThisPage()">
    <table border=0><tr><td><h2 id=title style="font-family:verdana">ECMAScript 5 Parser</h2></td></tr></table>

    <div id=instructions style="visibility: visible; display: block">
      <table bgcolor=#f9f9f9 cellpadding=2
             style="border: 1px solid #333333;
             padding: .2em .2em .2em .2em;
             margin-bottom: .4em;
             font-size: 11pt;
             font-family:verdana;
             margin-top: .1em">
        <tr><td>
	    I'm an <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript 5</a> parser.
	    In the textfield below, enter some ECMAScript 5 source code.
        If text is selected, I will only parse the selected part of the source.
        Otherwise, I parse the entire input. I output the AST
        in a simple <a href="http://code.google.com/p/es-lab/wiki/JsonMLASTFormat">JsonML format</a>.
      </td></tr></table>
    </div>

    <div align="center" id=instructions style="visibility: visible; display: block">
      <table bgcolor=#f9f9f9 cellpadding=2
             style="border: 1px solid #333333;
             margin-bottom: .2em;
             font-size: 9pt;
             font-family:verdana;
             color: black;
             background: orange;
             width: 40%;
             margin-top: .1em">
        <tr><td>
	    Note: I'm a work-in-progress version.
	    I may also still have <a href="http://code.google.com/p/es-lab/issues/list?can=2&q=label%3AParser">issues</a>.
      </td></tr></table>
    </div>
    
    <form id=workspaceForm>
      <span style="font-family:verdana;font-size:10pt">Source</span>
      <input type=button value="+/-" onClick="toggleVisible('source')">
      <br>
      <div id=source style="visibility: visible; display: block">        
        <p style="background-color: transparent;"><textarea name="source" style="
           border: 2px solid black;
           color: black;
           font-family: monospace, monaco;
           font-size: 10pt;
           height: 3in;
           overflow: auto;
           padding: 0.5em;
           width: 100%;"></textarea>

        <center><input type=button
               value="Parse it"
               onClick="parseIt()"
               style="margin-bottom: .4em;
                      background-color: lightgreen;
                      border: 2px solid black;
                      font-family: verdana;
                      font-size: 16pt;
                      color: black;"><br></center>
        
      </div>
      <span style="font-family:verdana;font-size:10pt" title="Shows the jsonML AST of the last thing that was parsed above">Produced AST</span>
      <input type=button value="+/-" onClick="toggleVisible('translation')">
      <br>
      <div id=translation style="visibility: hidden; display: none">
        <p style="background-color: transparent;"><textarea name="translation" style="
           border: 2px solid black;
           color: black;
           font-family: monospace, monaco;
           font-size: 10pt;
           height: 3in;
           overflow: auto;
           padding: 0.5em;
           width: 100%;"></textarea>
        
      </div>
     
      <div align="center" style="font-family:verdana;">
        <span style="padding: .2em .2em .2em .2em; border: 1px solid lightgrey">
          Parse as:
        <label for="Program"><input id="Program" type="radio" name="rules" checked="" value="Program"> Program</label>
        <label for="Expression"><input id="Expression" type="radio" name="rules" value="ExpressionOnly"> Expression</label>
        </span>
        <span style="padding: .2em .2em .2em .2em"> </span>
        <span style="padding: .2em .2em .2em .2em; border: 1px solid lightgrey">
        <label for="Generate position info"><input id="positionInfo" type="checkbox" align="left"> Generate position info</label>
        </span>
      </div>
      <p></p>
      <div align="center" style="color: darkgrey;font-family:verdana;font-size: 8pt">Copyright &#169; 2009-2010 <a href="http://code.google.com/p/es-lab">es-lab</a>. Created using <a href="http://tinlizzie.org/ometa">OMeta/JS</a>. This page modelled after <a href="http://www.jslint.com">JSLint</a>.</div>
    </form>

  <script type="text/javascript">
	var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
	document.write(original_unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
  </script>
  <script type="text/javascript">
	try {
	var pageTracker = _gat._getTracker("UA-12132825-1");
	pageTracker._trackPageview();
	} catch(err) {}</script>
  </body>
</html>

